/**
 * Copyright (C) 2009 - 2013 SC 4ViewSoft SRL
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.achartengine;

import android.content.Context;

import org.achartengine.chart.BarChart;
import org.achartengine.chart.BarChart.Type;
import org.achartengine.chart.BubbleChart;
import org.achartengine.chart.CombinedXYChart;
import org.achartengine.chart.CubicLineChart;
import org.achartengine.chart.DialChart;
import org.achartengine.chart.DoughnutChart;
import org.achartengine.chart.LineChart;
import org.achartengine.chart.PieChart;
import org.achartengine.chart.RangeBarChart;
import org.achartengine.chart.ScatterChart;
import org.achartengine.chart.SupportBarChart;
import org.achartengine.chart.SupportCubicLineChart;
import org.achartengine.chart.TimeChart;
import org.achartengine.chart.XYChart;
import org.achartengine.model.CategorySeries;
import org.achartengine.model.MultipleCategorySeries;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.DefaultRenderer;
import org.achartengine.renderer.DialRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;

/**
 * Utility methods for creating chart views or intents.
 */
public class ChartFactory {

    /**
     * The key for the chart data.
     */
    public static final String CHART = "chart";

    /**
     * The key for the chart graphical activity title.
     */
    public static final String TITLE = "title";

    private ChartFactory() {
        // empty
    }

    /**
     * Creates a line chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @return a line chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final GraphicalView getLineChartView(Context context,
                                                       XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
        checkParameters(dataset, renderer);
        XYChart chart = new LineChart(dataset, renderer);
        return new GraphicalView(context, chart);
    }

    public static final GraphicalView getSupportLineChartView(Context context,
                                                       XYMultipleSeriesDataset dataset,
                                                       XYMultipleSeriesRenderer renderer) {
        checkParameters(dataset, renderer);
        XYChart chart = new LineChart(dataset, renderer);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a cubic line chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @return a line chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final GraphicalView getCubeLineChartView(Context context,
                                                           XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness) {
        checkParameters(dataset, renderer);
        XYChart chart = new CubicLineChart(dataset, renderer, smoothness);
        return new GraphicalView(context, chart);
    }

    public static final GraphicalView getSupportCubeLineChartView(Context context,
                                                                  XYMultipleSeriesDataset dataset,
                                                                  XYMultipleSeriesRenderer renderer,
                                                                  float smoothness) {
        checkParameters(dataset, renderer);
        XYChart chart = new SupportCubicLineChart(dataset, renderer, smoothness);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a scatter chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @return a scatter chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final GraphicalView getScatterChartView(Context context,
                                                          XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
        checkParameters(dataset, renderer);
        XYChart chart = new ScatterChart(dataset, renderer);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a bubble chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @return a scatter chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final GraphicalView getBubbleChartView(Context context,
                                                         XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
        checkParameters(dataset, renderer);
        XYChart chart = new BubbleChart(dataset, renderer);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a time chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @param format   the date format pattern to be used for displaying the X axis
     *                 date labels. If null, a default appropriate format will be used.
     * @return a time chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final GraphicalView getTimeChartView(Context context,
                                                       XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String format) {
        checkParameters(dataset, renderer);
        TimeChart chart = new TimeChart(dataset, renderer);
        chart.setDateFormat(format);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a bar chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @param type     the bar chart type
     * @return a bar chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final GraphicalView getBarChartView(Context context,
                                                      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {
        checkParameters(dataset, renderer);
        XYChart chart = new BarChart(dataset, renderer, type);
        return new GraphicalView(context, chart);
    }


    public static final GraphicalView getSupportBarChartView(Context context,
                                                      XYMultipleSeriesDataset dataset,
                                                      XYMultipleSeriesRenderer renderer,
                                                      SupportBarChart.Type type) {
        checkParameters(dataset, renderer);
        XYChart chart = new SupportBarChart(dataset, renderer, type);
        return new GraphicalView(context, chart);
    }


    /**
     * Creates a range bar chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @param type     the range bar chart type
     * @return a bar chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final GraphicalView getRangeBarChartView(Context context,
                                                           XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {
        checkParameters(dataset, renderer);
        XYChart chart = new RangeBarChart(dataset, renderer, type);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a combined XY chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @param types    the chart types (cannot be null)
     * @return a combined XY chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if a dataset number of items is different than the number of
     *                                  series renderers or number of chart types
     */
    public static final GraphicalView getCombinedXYChartView(Context context,
                                                             XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String[] types) {
        if (dataset == null || renderer == null || types == null
                || dataset.getSeriesCount() != types.length) {
            throw new IllegalArgumentException(
                    "Dataset, renderer and types should be not null and the datasets series count should be equal to the types length");
        }
        checkParameters(dataset, renderer);
        CombinedXYChart chart = new CombinedXYChart(dataset, renderer, types);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a pie chart view that can be used to start the graphical view
     * activity.
     *
     * @param context  the context
     * @param dataset  the category series dataset (cannot be null)
     * @param renderer the series renderer (cannot be null)
     * @return a pie chart view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset number of items is different than the number of
     *                                  series renderers
     */
    public static final GraphicalView getPieChartView(Context context, CategorySeries dataset,
                                                      DefaultRenderer renderer) {
        checkParameters(dataset, renderer);
        PieChart chart = new PieChart(dataset, renderer);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a dial chart view that can be used to start the graphical view
     * activity.
     *
     * @param context  the context
     * @param dataset  the category series dataset (cannot be null)
     * @param renderer the dial renderer (cannot be null)
     * @return a pie chart view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset number of items is different than the number of
     *                                  series renderers
     */
    public static final GraphicalView getDialChartView(Context context, CategorySeries dataset,
                                                       DialRenderer renderer) {
        checkParameters(dataset, renderer);
        DialChart chart = new DialChart(dataset, renderer);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a doughnut chart view that can be used to start the graphical
     * view activity.
     *
     * @param context  the context
     * @param dataset  the multiple category series dataset (cannot be null)
     * @param renderer the series renderer (cannot be null)
     * @return a pie chart view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset number of items is different than the number of
     *                                  series renderers
     */
    public static final GraphicalView getDoughnutChartView(Context context,
                                                           MultipleCategorySeries dataset, DefaultRenderer renderer) {
        checkParameters(dataset, renderer);
        DoughnutChart chart = new DoughnutChart(dataset, renderer);
        return new GraphicalView(context, chart);
    }


    /**
     * Checks the validity of the dataset and renderer parameters.
     *
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    private static void checkParameters(XYMultipleSeriesDataset dataset,
                                        XYMultipleSeriesRenderer renderer) {
        if (dataset == null || renderer == null
                || dataset.getSeriesCount() != renderer.getSeriesRendererCount()) {
            throw new IllegalArgumentException(
                    "Dataset and renderer should be not null and should have the same number of series");
        }
    }

    /**
     * Checks the validity of the dataset and renderer parameters.
     *
     * @param dataset  the category series dataset (cannot be null)
     * @param renderer the series renderer (cannot be null)
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset number of items is different than the number of
     *                                  series renderers
     */
    private static void checkParameters(CategorySeries dataset, DefaultRenderer renderer) {
        if (dataset == null || renderer == null
                || dataset.getItemCount() != renderer.getSeriesRendererCount()) {
            throw new IllegalArgumentException(
                    "Dataset and renderer should be not null and the dataset number of items should be equal to the number of series renderers");
        }
    }

    /**
     * Checks the validity of the dataset and renderer parameters.
     *
     * @param dataset  the category series dataset (cannot be null)
     * @param renderer the series renderer (cannot be null)
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset number of items is different than the number of
     *                                  series renderers
     */
    private static void checkParameters(MultipleCategorySeries dataset, DefaultRenderer renderer) {
        if (dataset == null || renderer == null
                || !checkMultipleSeriesItems(dataset, renderer.getSeriesRendererCount())) {
            throw new IllegalArgumentException(
                    "Titles and values should be not null and the dataset number of items should be equal to the number of series renderers");
        }
    }

    private static boolean checkMultipleSeriesItems(MultipleCategorySeries dataset, int value) {
        int count = dataset.getCategoriesCount();
        boolean equal = true;
        for (int k = 0; k < count && equal; k++) {
            equal = dataset.getValues(k).length == dataset.getTitles(k).length;
        }
        return equal;
    }

}
